/*
   R2O (Relational to Object) is a free ORM ( Object- realtional mapping) tool.
   Copyright (C) 2010 Patrick Bashizi.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this package; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package com.pbash.r2o.generationTools;

import com.pbash.r2o.dataAccess.ConnectionManager;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;
import com.pbash.r2o.util.StringOperation;
import static com.pbash.r2o.util.StringOperation.upFirstChar;

/**
 *
 * @author Bash
 */
public class JavaFileGenerator {

    private String fileName;
    private String projectName;
    private String packageName;
    private File file;
    private FileOutputStream fos;
    private PrintWriter out;
    static ConnectionManager cm;

    public void writeFile(TableRepresentation tr) throws FileNotFoundException,
            IOException {
        String fullPath = "src\\" + packageName;
        file = new File(fullPath);
        if (!file.exists()) {
            file.mkdir();
        }
        fos = new FileOutputStream(fullPath + "\\" + fileName);
        out = new PrintWriter(fos);

        out.println("// Generated by R2O 1.0.Developped by Patrick Bashizi Mutuzi. All right reserved.");
        out.println();

        out.println("package " + getPackageName() + ";");
        out.println();
        out.println();

        out.println("import com.pbash.r2o.dataAccess.DataObject;");
        out.println("import java.sql.*;");
        out.println("import java.util.ArrayList;");

        out.println();
        out.println();

        out.print("public class " + tr.getTableName() + " extends DataObject{");
        out.println();
        out.println();

        ArrayList<String> h = tr.getFieldsHash();

        StringTokenizer tok = null;

        for (String key : h) {
            tok = new StringTokenizer(key, ",");
//            Class cl = (Class) h.get(key);
            out.println("private " + tok.nextToken() + " " + tok.nextToken() + ";");
        }
        out.println();
        out.println();
        out.println();

        //constructor

        out.println("public " + tr.getTableName() + "(){" + "\n\n" + "}\n\n");

        out.print("public " + tr.getTableName() + "(");
        String par = "";
        for (String key : h) {
            tok = new StringTokenizer(key, ",");

            par = par + tok.nextToken() + " " + tok.nextToken() + ",";
            //out.print(par.substring(par.length()-1));
        }
        par = StringOperation.removeLastComma(par);
        out.println(par);
        out.println("){");

        for (String s : h) {
            tok = new StringTokenizer(s, ",");
            tok.nextToken();
            String var = tok.nextToken();
            out.println("this." + var + "=" + var + ";");
        }
        out.println("}");//end constructor

//fields encapsulation
//getters
        for (String s : h) {
            tok = new StringTokenizer(s, ",");
            String classe = tok.nextToken();
            String var = tok.nextToken();
            out.println("public " + classe + "  get" + upFirstChar(var + "()")
                    + "{\n" + "return this." + var + ";\n}");
        }
//setters
        for (String s : h) {
            tok = new StringTokenizer(s, ",");

            String classe = tok.nextToken();
            String var = tok.nextToken();

            out.println("public void set" + upFirstChar(var) + "(" + classe + " " + var
                    + "){\n this." + var + "=" + var + ";\n}");
        }
//create

        String createSQL = "insert into " + tr.getTableName() + " values(";
        for (int i = 0; i < h.size(); i++) {

            createSQL = createSQL + "?,";
        }
        createSQL = StringOperation.removeLastComma(createSQL) + ")";

        out.println("\npublic boolean create() throws Exception{\nString createSQL=\"" + createSQL + "\";");
        out.println("statement = cm.getConnexion().prepareStatement(createSQL);");
        out.println("\nboolean executed=false;");
        int j = 1;
        for (String s : h) {
            tok = new StringTokenizer(s, ",");

            String classe = tok.nextToken();
            String var = tok.nextToken();
            out.println("statement.set" + (classe.equals("Integer") ? "Int" : classe) + "(" + j + "," + var + ");");
            j++;

        }
        out.println("executed=statement.execute();\n");
        out.println("return executed;\n}");


        //read a dataObject(fill thes current object whith datarow values)

        out.println("\npublic void read(String keyValue) throws Exception{");
        String readSQL = "select * from " + tr.getTableName() + " where id" + tr.getTableName() + "=?";
        out.println("\nString readSQL=\"" + readSQL + "\";");

        out.println("statement = cm.getConnexion().prepareStatement(readSQL);");


        out.println("statement.setString(1,keyValue);");
        out.println(" ResultSet rst=statement.executeQuery();\n");

        int k = 1;
        out.println("while (rst.next()) {");

        for (String s : h) {
            tok = new StringTokenizer(s, ",");

            String classe = tok.nextToken();
            String var = tok.nextToken();
            out.println("this.set" + upFirstChar(var)
                    + "(rst.get" + (classe.equals("Integer") ? "Int" : classe) + "(" + k + "));");
            k++;
        }
        out.println("\n}\n}\n");

        //update method overrided

        out.println("public int update() throws Exception{");

        // out.println(tr.getTableName() + " obj=  (" + tr.getTableName() + ")newValuesOwner;");

        String updateSQL = "update " + tr.getTableName() + " set ";

        for (String s : h) {
            tok = new StringTokenizer(s, ",");
            String classe = tok.nextToken();
            String var = tok.nextToken();
            updateSQL += var + "=? , ";
        }

        updateSQL = StringOperation.removeLast(updateSQL, 2);
        updateSQL += " where " + tr.getPrimaryKey();

        out.print("String updateSQL=\"" + updateSQL + " = ?\";\n");
        //  out.print("=\"+ this.get" + upFirstChar(tr.getPrimaryKey()) + "();\n");

        out.println("statement = cm.getConnexion().prepareStatement(updateSQL);");
        int u = 1;
        for (String s : h) {
            tok = new StringTokenizer(s, ",");

            String classe = tok.nextToken();
            String var = tok.nextToken();
            out.println("statement.set" + (classe.equals("Integer") ? "Int" : classe) + "(" + u + "," + var + ");");
            u++;

        }
        out.println("statement.set" + (tr.getPrimaryKeyType().equals("Integer") ? "Int" : tr.getPrimaryKeyType()) + "(" + (u) + "," + tr.getPrimaryKey() + ");");

        out.println("int rowafect=statement.executeUpdate();");
        out.println("return rowafect;");
        out.println("}");

        //   getAll
        out.println("public ArrayList<DataObject> getAll() throws Exception {");
        out.println("ArrayList<DataObject> all = new ArrayList<DataObject>();");

        out.println("String allQuery = \" select * from " + tr.getTableName() + "\";");
        out.println("statement = cm.getConnexion().prepareStatement(allQuery);");
        out.println("ResultSet rst = statement.executeQuery();");
        // Article art = new Article();
        out.println(tr.getTableName() + " an" + tr.getTableName() + ";");


        out.println("synchronized(all){");
        out.println("while (rst.next()) {");

        out.println("an" + tr.getTableName() + "= new " + tr.getTableName() + "();");
        int p = 1;
        for (String s : h) {

            tok = new StringTokenizer(s, ",");

            String classe = tok.nextToken();
            String var = tok.nextToken();
            out.println(" an" + tr.getTableName() + ".set" + upFirstChar(var)
                    + "(rst.get" + (classe.equals("Integer") ? "Int" : classe) + "(" + p + "));");
            p++;
        }
        out.println(" all.add(" + " an" + tr.getTableName() + ");");

        out.println("\n}return all;\n}\n}\n");


        //delete

        out.println("public int delete(String key) throws Exception{");
        out.println("String deleteSQL = \"delete from " + tr.getTableName() + " where "+tr.getPrimaryKey()+" = ?\";");
        out.println(" statement = cm.getConnexion().prepareStatement(deleteSQL);");
        out.println("statement.setString(1, key);");

        out.println("int rowafect = statement.executeUpdate();");
        out.println("return rowafect;\n}");

        //
        out.println("}"); //end of class

        out.close();
    }

    public static ArrayList<TableRepresentation> generate() {
        System.out.println("R2O Generator initialization...");
        cm = ConnectionManager.getInstance();
        ArrayList<TableRepresentation> tReps = new ArrayList<TableRepresentation>();
        try {
            cm.makeConnection();
            for (int i = 0; i < cm.getTableNames().length; i++) {
                TableRepresentation tr = new TableRepresentation();
                String tn = cm.getTableNames()[i];

                ArrayList<String> h = cm.getColumnNamesAndClassArr(tn);
                tr.setTableName(tn);
                tr.setFieldsHash(h);
                tr.setPrimaryKey(cm.getPrimaryKey(tn));
                tr.setPrimaryKeyType(cm.getPrimaryKeyClassName());
                tReps.add(tr);

            }

            cm.clean();
            // System.out.println("connection closed.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tReps;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    public static void main(String[] args) {
        try {
            long begin = System.currentTimeMillis();
            ArrayList<TableRepresentation> al = JavaFileGenerator.generate();
            System.out.println("Generating +" + al.size() + " classes:" + "\n");
            for (TableRepresentation tr : al) {

                JavaFileGenerator gen = new JavaFileGenerator();
                gen.setPackageName("pojos");

                gen.setFileName(tr.getTableName() + ".java");
                System.out.println(gen.getFileName());
                gen.writeFile(tr);
            }
            System.out.println("\nSuccess !");
            long end = System.currentTimeMillis();

            long dur = ((end - begin));
            System.out.println("Duration : " + dur + " millisec.");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
